package com.mdinic.blogovi.service;

import java.util.Properties;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.regex.PatternSyntaxException;

import javax.annotation.PreDestroy;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;

import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.mail.javamail.MimeMessagePreparator;
import org.springframework.stereotype.Service;

/**
 * Implementation of interface {@link EmailService} and extension of
 * {@link JavaMailSenderImpl}.
 * 
 * @author mdinic
 * 
 */
@Service
class EmailSenderImpl extends JavaMailSenderImpl implements EmailSender {

    private static final Logger LOG = Logger.getLogger(EmailSenderImpl.class);

    /**
     * instance of service executor. used to queue outgoing emails.
     */
    private static final ExecutorService EXECUTOR = Executors.newCachedThreadPool();

    @Override
    public void sendMail(final String mailTo, final String mailFrom, final String subject, final String content) {

        final Runnable command = new Runnable() {
            @Override
            public void run() {
                LOG.info("Sending an email to '" + mailTo + "' subject: " + subject);
                final MimeMessagePreparator preparator = new MimeMessagePreparator() {
                    @Override
                    public void prepare(final MimeMessage mimeMessage) throws MessagingException {
                        final MimeMessageHelper message = new MimeMessageHelper(mimeMessage, "UTF-8");
                        message.setTo(mailTo);
                        message.setFrom(mailFrom);
                        message.setSubject(subject);
                        message.setText(content, true);
                    }
                };
                send(preparator);
            }
        };

        EXECUTOR.execute(command);
    }

    /**
     * Will be called by spring when before this service gets disposed.
     */
    @PreDestroy
    public void cleanUp() {
        EXECUTOR.shutdown();
    }

    /**
     * Setter for email server host. This method will be called by spring.
     * 
     * @param host
     */
    @Value("${mail.smtp.host}")
    public void setMailHost(final String host) {
        super.setHost(host);
    }

    /**
     * Setter for email server port. This method will be called by spring.
     * 
     * @param port
     */
    @Value("${mail.smtp.port}")
    public void setMailPort(final int port) {
        super.setPort(port);
    }

    /**
     * Setter for email smtp username. This method will be called by spring.
     * 
     * @param username
     */
    @Value("${mail.username}")
    public void setMailUsername(final String username) {
        super.setUsername(username);
    }

    /**
     * Setter for email server password. This method will be called by spring.
     * 
     * @param password
     */
    @Value("${mail.password}")
    public void setMailPassword(final String password) {
        super.setPassword(password);
    }

    /**
     * Setter for email server protocol. This method will be called by spring.
     * 
     * @param protocol
     */
    @Value("${mail.protocol}")
    public void setMailProtocol(final String protocol) {
        super.setProtocol(protocol);
    }

    /**
     * Setter for email server properties. This method will be called by spring.
     * Properties should be separated with ';'. <br />
     * E.g. mail.debug=true;mail.smtps.auth=true
     * 
     * @param properties
     */
    @Value("${mail.properties}")
    public void setJavaMailProperties(final String properties) {
        if (StringUtils.isEmpty(properties)) {
            return;
        }
        try {
            final Properties javaMailProperties = new Properties();
            final String[] props = properties.split(";");
            for (final String property : props) {
                final String[] keyValue = property.split("=");
                LOG.info("found email property: " + keyValue[0] + ":" + keyValue[1]);
                javaMailProperties.put(keyValue[0], keyValue[1]);
            }
            super.setJavaMailProperties(javaMailProperties);
        } catch (final PatternSyntaxException e) {
            throw new IllegalArgumentException("Error while parsing email properties", e);
        } catch (final ArrayIndexOutOfBoundsException e) {
            throw new IllegalArgumentException("Error while reading parsed email properties", e);
        }
    }

}
